<?php

namespace Cloud\Server;

use Firebase\JWT\JWT;
use Redis;
use Swoole\Coroutine\Http\Client;
use Swoole\Timer;
use Swoole\WebSocket\Server as SwoWsServer;
use Swoole\Http\Request as SwoRequest;
use Swoole\Http\Response as SwoResponse;

class Dispatcher
{
    public function register(Route $route, SwoWsServer $server, int $fd, array $data)
    {
        $redis = $route->getRedis();

        $key = $route->serverKey;

        $redis->sAdd($key, $value = json_encode([
            'ip' => $data['ip'],
            'port' => $data['port']
        ]));

        echo ($redis->srandmember($key)) . PHP_EOL;

        /*
         * timer clear redis data if connect not exists
         */
        Timer::tick(4000, function (
            int $timerId,
            SwoWsServer $server,
            Redis $redis,
            int $fd,
            string $key,
            string $value) {
            if (! $server->exist($fd)) {
                $redis->sRem($key, $value);
                $server->clearTimer($timerId);
            }
        }, $server, $redis, $fd, $key, $value);
    }

    /**
     * Note: 登录
     *
     * @param Route $route
     * @param SwoRequest $swoRequest
     * @param SwoResponse $swoResponse
     * @return void
     * @author: Zhao Zhiqiang
     * @since: 2021/6/4 16:25
     */
    public function login(Route $route, SwoRequest $swoRequest, SwoResponse $swoResponse)
    {
        $server = json_decode($this->getIMServer($route), true);
        $url = implode(':', $server);

        $uid = $swoRequest->post['id'];

        $token = $this->createToken($url, $uid);

        $swoResponse->header('Access-Control-Allow-Origin', '*');
        $swoResponse->header('Access-Control-Allow-Methods', 'POST,GET,');

        return $swoResponse->end(json_encode(['token' => $token, 'url' => $url]));
    }

    /**
     * Note: 生成 Token
     *
     * @param string $url
     * @return string
     * @author: Zhao Zhiqiang
     * @since: 2021/6/4 16:24
     */
    protected function createToken(string $url, $uid = 0): string
    {
        $key = 'cloud';
        $time = time();
        $payload = array(
            "iss" => "http://example.org",
            "aud" => "http://example.com",
            "iat" => $time,
            "nbf" => $time,
            'exp' => $time + 24 * 60 * 60,
            'data' => [
                'uid' => $uid,
                'name' => 'Leroy' . $uid,
                'server_url' => $url
            ]
        );

        return JWT::encode($payload, $key);
    }

    protected function getIMServer(Route $route)
    {
        $servers = $route->getRedis()->sMembers($route->getServerKey());

        if (!$servers) {
            return false;
        }

        return $route->getAlgorithm()->getNextAddr($servers);
    }

    /**
     * 向所有 IM-Server 发送广播
     *
     * @param Route $route
     * @param SwoWsServer $swoServer
     * @param int $fd
     * @param array $data
     */
    public function routeBroadcast(Route $route, SwoWsServer $swoServer, int $fd, array $data)
    {
        $servers = $route->getRedis()->sMembers($route->getServerKey());

        // IM Server 服务器对 route 进行 jwt 验证
        $token = $this->createToken($route->getHost() . ":" . $route->getPort());
        $headers = [
            'sec-websocket-protocol' => $token
        ];

        foreach ($servers as $server) {
            $server = json_decode($server, true);

            $route->send($server, $data, $headers);
        }
    }
}